package zzk.activiti;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.*;
import java.util.List;

/**
 * @author 天真热
 * @create 2021-10-19 16:08
 * @desc
 **/
@Controller
@RequestMapping("activiti")
public class ActivitiDemo {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;


//================================================================activiti接口基础api示例开始=========================================================================================
    /**
     * 部署流程
     */
    @RequestMapping("createProcesses")
    @ResponseBody
    public void createProcesses() {
        //使用获取RepositoryService进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("static/bpmn/demo.bpmn")//添加bpmn资源
                .addClasspathResource("static/bpmn/demo.png")//添加png资源
                .name("员工请假审批流程")
                .deploy();//部署流程
        //输出流程部署的信息
        System.out.println("流程部署id：" + deployment.getId());
        System.out.println("流程部署名称：" + deployment.getName());
    }

    /**
     * 查询流程的定义
     */
    @RequestMapping("searchProcess")
    @ResponseBody
    public void searchProcess() {
        String id = "evection";
        //获取ProcessDefinitionQuery对象，用来查询操作
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKeyLike(id)
                .orderByProcessDefinitionVersion()//安装版本信息
                .desc()//倒序
                .list();
        //输出流程定义的信息
        for (ProcessDefinition processDefinition : list) {
            System.out.println("流程定义的id：" + processDefinition.getId());
            System.out.println("流程定义的name：" + processDefinition.getName());
            System.out.println("流程定义的key：" + processDefinition.getKey());
            System.out.println("流程定义的version：" + processDefinition.getVersion());
            System.out.println("流程部署的id：" + processDefinition.getDeploymentId());
        }

    }


    /**
     * 删除流程
     */
    @RequestMapping("delProcessl")
    @ResponseBody
    public void delProcessl() {
        String id = "d70e83b1-b238-11ef-8920-04ed33b13d42";
        //设置true，择优级联删除的效果。false如果已有实例，则会删除错误
        repositoryService.deleteDeployment(id, true);

    }

    /**
     * 获取流程里面的资源文件
     */
    @RequestMapping("searchProcesslFile")
    @ResponseBody
    public void searchProcesslFile() throws IOException {
        String id = "evection";
        //查询器
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(id)
                .singleResult();
        //获取流程部署id
        String deploymentId = processDefinition.getDeploymentId();
        //通过repositoryService对象的相关方法来获取图片信息和bpmn信息
        //png图片
        InputStream pngInput = repositoryService
                .getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
        //bpmn 文件的流
        InputStream bpmnInput = repositoryService
                .getResourceAsStream(deploymentId, processDefinition.getResourceName());
        //文件的保存
        File filePng = new File("D:/学习/activiti/evection.png");
        File fileBpmn = new File("D:/学习/activiti/evection.bpmn");
        OutputStream pngOut = new FileOutputStream(filePng);
        OutputStream bpmnOut = new FileOutputStream(fileBpmn);

        //生效需要放开
        IOUtils.copy(pngInput, pngOut);
        IOUtils.copy(bpmnInput, bpmnOut);
        pngInput.close();
        pngOut.close();
        bpmnInput.close();
        bpmnOut.close();

    }


    /**
     * 创建流程实例
     */
    @RequestMapping("addApplication")
    @ResponseBody
    public void addApplication() {
        String businessKey = "evection";
        //启动一个流程实例
        //ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey);
        //启动一个流程实例,设置业务id,长度最大255，通过processInstance.getBusinessKey()获取
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey,"evection");
        System.out.println("流程定义id：" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id：" + processInstance.getId());
        System.out.println("当前活动id：" + processInstance.getActivityId());
    }

    /**
     * 查询流程下存在哪些实例
     * 可通过.processInstanceId等相关属性过滤
     */
    @RequestMapping("searchProcessRunInstance")
    @ResponseBody
    public void searchProcessRunInstance() {
        String key = "evection";
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
        //输出流程定义的信息
        for (ProcessInstance processInstance : list) {
            System.out.println("流程实例id：" + processInstance.getProcessInstanceId());
            System.out.println("所属流程定义id：" + processInstance.getProcessDefinitionId());
            System.out.println("是否完成：" + processInstance.isEnded());
            System.out.println("是否暂停：" + processInstance.isSuspended());
            System.out.println("当前活动标识：" + processInstance.getActivityId());
            System.out.println("业务关键字：" + processInstance.getBusinessKey());
            System.out.println("------------" );
        }

    }


    /**
     * 根据流程和当前处理人获取实例对象
     */
    @RequestMapping("searchTaskBusinessKey")
    @ResponseBody
    public void searchTaskBusinessKey() {
        //查询流程定义对象
        List<Task> task = taskService.createTaskQuery()
                .processDefinitionKey("evection")
                .taskAssignee("manager")
                .list();
        //使用task获取实例id
        String processInstanceId = task.get(0).getProcessInstanceId();
        //使用id获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        //根据processInstance获取id
        String businessKey = processInstance.getBusinessKey();
        System.out.println("实例id=" + businessKey);
    }

    /**
     * 任务查询
     */
    @RequestMapping("searchTask")
    @ResponseBody
    public void searchTask() {
        String assignee = "manager";
        String id = "evection";
        //根据流程的key和任务负责人 查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(id)
                .taskAssignee(assignee)
                .list();
        //输出当前用户具有的任务
        for (Task task : list) {
            System.out.println("流程实例id：" + task.getProcessDefinitionId());
            System.out.println("任务id：" + task.getId());
            System.out.println("任务负责人：" + task.getAssignee());
            System.out.println("任务名称：" + task.getName());
        }

    }


    /**
     * 流程任务的处理(根据流程id和处理人获取数据)
     */
    @RequestMapping("solveTask")
    @ResponseBody
    public void solveTask() {
        String assignee = "worker";
        String id = "evection";
        //根据流程的key和任务负责人 查询任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(id)
                .taskAssignee(assignee)
                .singleResult();
        //完成任务，跳到下一个流程
        taskService.complete(task.getId());

    }


    /**
     * 流程任务的处理(根据实例id)
     */
    @RequestMapping("solveTaskForSl")
    @ResponseBody
    public void solveTaskForSl() {
        //根据流程的key和任务负责人 查询任务
        Task task = taskService.createTaskQuery()
                .executionId("cdf0924f-b239-11ef-8920-04ed33b13d42")
                .singleResult();
        //完成任务，跳到下一个流程
        taskService.complete(task.getId());

    }


    /**
     * 流程历史信息查看
     * 即时删除了流程，但是流程的历史信息还是会被保存下来，存在hi**表中
     */
    @RequestMapping("searchHistoricActivityInstance")
    @ResponseBody
    public void searchHistoricActivityInstance() {
        String id = "evection:1:c401b1bd-b239-11ef-8920-04ed33b13d42";
        //获取actinst表的查询对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        HistoricActivityInstanceQuery historicActivityInstanceQuery1 = historicActivityInstanceQuery.processDefinitionId(id);
        //排序
        historicActivityInstanceQuery1.orderByHistoricActivityInstanceStartTime().desc();
        //获取查询结果
        List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();
        //输出查询结果
        for (HistoricActivityInstance hi : list) {
            System.out.println(hi.getActivityId());
            System.out.println("步骤："+hi.getActivityName());
            System.out.println(hi.getActivityType());
            System.out.println("操作人："+hi.getAssignee());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
        }
    }

    /**
     * 全部流程实例挂起和激活
     */
    @RequestMapping("allLockOrOpenPeocess")
    @ResponseBody
    public void allLockOrOpenPeocess() {
        String id = "evection";
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(id)
                .singleResult();
        //获取流程的状态
        boolean suspended = processDefinition.isSuspended();
        String pdId = processDefinition.getId();
        //如果激活就挂起，挂起就激活
        if (suspended) {
            //表示当前是挂起的，需要激活。
            //参数：流程定义id、是否激活、激活时间
            repositoryService.activateProcessDefinitionById(pdId, true, null);
            System.out.println("流程定义：" + pdId + ",已激活");
        } else {
            //激活状态，则需要挂起
            //参数：流程定义id、是否挂起、挂起时间
            repositoryService.suspendProcessDefinitionById(pdId, true, null);
            System.out.println("流程定义：" + pdId + ",已挂起");
        }


    }
    /**
     * 单个流程实例挂起和激活
     */
    @RequestMapping("singleLockOrOpenPeocess")
    @ResponseBody
    public void singleLockOrOpenPeocess() {
        //task表的proc_inst_id
        String id = "cdf06b3e-b239-11ef-8920-04ed33b13d42";
        //获取实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(id)
                .singleResult();
        //获取状态
        boolean suspended = processInstance.isSuspended();
        String pdId = processInstance.getId();
        if (suspended) {
            //表示当前是挂起的，需要激活
            runtimeService.activateProcessInstanceById(pdId);
            System.out.println("流程定义：" + pdId + ",已激活");
        } else {
            //激活状态，则需要挂起
            runtimeService.suspendProcessInstanceById(pdId);
            System.out.println("流程定义：" + pdId + ",已挂起");
        }

    }

    /**
     * 判断用户是否有操作权限
     */
    @RequestMapping("CheckAuthority")
    @ResponseBody
    public void CheckAuthority() {
        //任务id
        String taskId = "df552bc7-b23b-11ef-9a67-04ed33b13d42";
        //任务负责人
        String assignee = "manager";
        //完成任务前需要校验该用户是否有权限操作
        //校验方法
        //根据任务id和任务负责人查询当前任务。如果查询有权限，则完成
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            System.out.println("有权限");
        } else {
            System.out.println("无权限");
        }
    }




//===================================================================activiti接口基础api示例结束======================================================================================



//===================================================================activiti接口进阶（变量启动）示例开始======================================================================================
    /**
     * 创建实例，并且指定启动人
     */
    @RequestMapping("startProcess")
    @ResponseBody
    public void startProcess() {
        String id = "evection";

        //设置流程启动人
        Authentication.setAuthenticatedUserId("worker");
        //可以带上业务单号10001
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id, "10001");
    }


    /**
     * 查看某人的流程记录，即我的申请
     */
    @RequestMapping("findProcessByUser")
    @ResponseBody
    public void findProcessByUser() {
        //act_hi_procinst表的start_user_id
        String id = "worker";
        //创建查询对象,查询该用户发起的流程
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
                .startedBy(id)
//                .finished()//已完成
//                .unfinished()//未完成
                .list();
        for (HistoricProcessInstance h : list) {
            System.out.println(h.getStartActivityId());
            System.out.println(h.getStartTime());
            System.out.println(h.getStartUserId());
        }

    }










}
